# -*- coding: utf-8 -*-
# @Time    : 2019/10/21 14:16
# @Author  : LiHaowen
# @Email   : lihaowen2017@163.com
# @File    : how_gen_work.py

# 1. python 中函数的工作原理

import inspect
frame = None


def foo():
    bar()


def bar():
    global frame
    frame = inspect.currentframe()

# python.exe会用一个叫做PyEval_EvalFramEx(c函数)去执行foo函数，
# 首先会创建一个栈帧(stack frame)
# python 一切皆对象， 栈帧对象，栈帧对象的上下文会运行字节码对象，
# 字节码对象全局唯一
# 当foo调用子函数，又会创建一个栈帧，新创建的栈帧上下文中去运行bar的字节码
# 所有的栈帧都是分配在堆内存上
# 堆内存的特性：不去释放堆内存则一直会存放在内存中
# 栈帧可以独立于调用者存在


import dis  # 反编译查看字节码
# print(dis.dis(foo))


foo()
print(frame.f_code.co_name)
caller_frame = frame.f_back  # f_back 指向调用者
print(caller_frame.f_code.co_name)


def gen_func():
    yield 1
    name = "b1"
    yield 2
    age = 30
    return "i1"
# 生成器对象分配在堆内存中，所以可以像函数的栈帧一样，独立于调用者存在。
# 拿到生成器对象，每次调用，都会重新生成栈帧，只要拿到生成器对象都会控制它继续往前走
# 在任何地方任何函数任何模块只要拿到生成器对象都可以控制，(暂停，继续)


gen = gen_func()
print(dis.dis(gen))
print(gen.gi_frame.f_lasti)  # 记录最近执行代码的字节码的位置
print(gen.gi_frame.f_locals)  # locals变量
next(gen)  # 控制生成器的暂停
print(gen.gi_frame.f_lasti)
print(gen.gi_frame.f_locals)
next(gen)
print(gen.gi_frame.f_lasti)
print(gen.gi_frame.f_locals)




